// ----------------
// Project:
// ESA Elevator
// ----------------
//
// ----------------
// Group: 163
// 2358569: Pascal Klink
// 2649456: Lukas Kreh
// ----------------
//
// Description:
// ----------------
// elevator next-floor-control
//
// Version History:
// ----------------
// 140116: set parameter FLOORS to 30
// 140116: set parameter FLOOR_BITS to 5

`timescale 1ns / 1ns

module next_floor_ctrl

          #(parameter FLOORS     = 30,
                      FLOOR_BITS =  5)

          (input  wire                          CLK,
           input  wire                          RESET,

           input  wire                          HALTED,
           input  wire [(FLOORS-1)          :0] DESTINATIONS,
           input  wire [((FLOORS*2)-1)      :0] FLOOR_REQUEST,
           input  wire [(FLOOR_BITS-1)      :0] CURRENT_FLOOR,
           
           output reg  [(FLOOR_BITS-1)      :0] NEXT_FLOOR);
       
/* =============================INSERT CODE HERE======================================*/ 

reg [(FLOOR_BITS-1):0] last_pos;
reg halted;
reg UP;
reg DOWN;
reg changeDir;
reg [(FLOOR_BITS-1)      :0] count_up;
reg [(FLOOR_BITS-1)      :0] count_down;
reg start_loop;
reg stop_up;
reg stop_down;
reg [(FLOOR_BITS-1):0] nextup;
reg [(FLOOR_BITS-1):0] nextdown;
reg [(FLOOR_BITS-1):0]maxUP;
reg [(FLOOR_BITS-1):0]minDOWN;

always@(posedge CLK)begin
	//reset everything
	if(RESET)begin
		NEXT_FLOOR=CURRENT_FLOOR;
		UP=1;
		DOWN=0;
		last_pos=CURRENT_FLOOR;
		nextup=CURRENT_FLOOR;
		nextdown=CURRENT_FLOOR;
		halted=0;
		count_up=0;
		count_down=0;
		stop_up=0;
		stop_down=0;
		start_loop=0;
		changeDir=0;
		maxUP=FLOORS;
		minDOWN=0;
	end 
	else begin
		//only start loop when either halted or the current floor has changed
		if(halted!=HALTED || last_pos!=CURRENT_FLOOR)begin
			halted=HALTED;	//refresh halted
			//get actual direction
			if(last_pos<CURRENT_FLOOR)begin
				UP=1;
				DOWN=0;
			end
			else begin 
				if(last_pos>CURRENT_FLOOR)begin
					DOWN=1;
					UP=0;
				end
			end
			//now refresh and reset all values needed for the loop
			last_pos=CURRENT_FLOOR;	
			count_up=CURRENT_FLOOR;
			count_down=CURRENT_FLOOR;
			//set nextup/down to CURRENT_FLOOR - in case there is no request
			nextup=CURRENT_FLOOR;
			nextdown=CURRENT_FLOOR;
			changeDir=0;
			stop_up=0;
			stop_down=0; 
			start_loop=1;
			maxUP=FLOORS;
			minDOWN=0;
		end 
		else begin
			//loop starts here
			if(start_loop)begin
				//UP
				if(!stop_up)begin
					//only if there are still floors to check
					if(count_up<maxUP)begin
						count_up=count_up+1;	//inc counter
						//if either there is an floor request (in UP-direction) or an halt-wish in this floor
						if(DESTINATIONS[count_up]==1 || FLOOR_REQUEST[(count_up*2)+1]==1)begin
							//save nextup and stop the up-loop
							nextup=count_up;
							stop_up=1;				
							//if UP is our direction, immediately set our result and stop the whole loop
							if(UP )begin
								NEXT_FLOOR=nextup;
								start_loop=0;
							end
						end
					end
					//if there is no request in UP direction, try to find something by counting 
					//from 0 to CURRENT_FLOOR and set changeDir to true so we can look if there 
					//is an result for the DOWN-direction.
					else begin
						if(!(count_up<FLOORS))begin	//only if normal loop was unsuccessful
							if(!(count_down>0))begin
								minDOWN=CURRENT_FLOOR;
								count_down=FLOORS;
								maxUP=CURRENT_FLOOR;
								count_up=0;
							end
							if(stop_down)begin
								stop_up=1; 
							end
							changeDir=1;
						end
						else begin	
							//if search finished, stop the loop
							stop_up=1;
						end
					end
				end 
				else begin 
					//if direction was DOWN but there was no result for DOWN-direction
					//or if the UP-loop already began to count backwards, set the result
					//from DOWN-Direction (if both had no result NEXT_FLOOR should be CURRENT_FLOOR then)
					if(((DOWN && stop_down) || (minDOWN!=0)) && changeDir)begin
						NEXT_FLOOR=nextup;
						start_loop=0;
					end
				end 
				//DOWN
				if(!stop_down)begin
					//only if there are still floors to check
					if(count_down>minDOWN)begin
						count_down=count_down-1;	//dec counter
						//if either there is an floor request (in DOWN-direction) or an halt-wish in this floor
						if(DESTINATIONS[count_down]==1 || FLOOR_REQUEST[(count_down*2)]==1)begin
							//save nextup and stop the down-loop
							nextdown[FLOOR_BITS-1:0]=count_down;
							stop_down=1;
							//if DOWN is our direction, immediately set our result and stop the whole loop
							if(DOWN)begin
								NEXT_FLOOR=nextdown;
								start_loop=0;
							end
						end
					end
					//if there is no request in DOWN direction, try to find something by counting 
					//from FLOORS to CURRENT_FLOOR and set changeDir to true so we can look if there 
					//is an result for the UP-direction.
					else begin
						if(!(count_down>0))begin	//only if normal loop was unsuccessful
							if(!(count_up<FLOORS))begin
								minDOWN=CURRENT_FLOOR;
								count_down=FLOORS;
								maxUP=CURRENT_FLOOR;
								count_up=0;
							end
							if(stop_up)begin
								stop_down=1;
							end
							changeDir=1;
						end
						else begin
							//if search finished, stop the loop
							stop_down=1;
						end
					end
				end 
				else begin
					//if direction was UP but there was no result for UP-direction
					//or if the UP-loop already began to count backwards, set the result
					//from DOWN-Direction (if both had no result NEXT_FLOOR should be CURRENT_FLOOR then)
					if(((UP && stop_up) || (maxUP!=FLOORS)) && changeDir)begin
						NEXT_FLOOR=nextdown;
						start_loop=0;
					end 
				end
			end 
		end
	end
end
 
/* ====================================================================================*/

endmodule
